<template>
	<div class="chat-container">
		<div class="chat-list" ref="listRef">
			<div v-for="(m, idx) in messages" :key="idx" class="chat-item" :class="m.role">
				<div class="avatar" v-if="m.role === 'ai'">{{ aiAvatar || '🤖' }}</div>
				<div class="avatar" v-else>{{ userAvatar || '👤' }}</div>
				<div class="chat-bubble" :class="m.role">{{ m.content }}</div>
			</div>
			<div v-if="isStreaming" class="muted">对方正在输入...</div>
		</div>
		<div class="chat-input">
			<textarea v-model="input" placeholder="输入消息，回车发送（Shift+Enter 换行）" @keydown.enter.exact.prevent="handleSend" @keydown.enter.shift="newline"></textarea>
			<button :disabled="!input.trim() || isStreaming" @click="handleSend">发送</button>
		</div>
	</div>
</template>

<script setup lang="ts">
import { ref, watch, nextTick, onBeforeUnmount } from 'vue';

export interface ChatMessage {
	role: 'user' | 'ai';
	content: string;
}

const props = defineProps<{
	// 发起 SSE 的方法，入参为用户输入内容，返回一个关闭函数
	startStream: (message: string) => () => void;
	aiAvatar?: string;
	userAvatar?: string;
}>();

const messages = ref<ChatMessage[]>([]);
const input = ref('');
const isStreaming = ref(false);
const listRef = ref<HTMLDivElement | null>(null);
let stopCurrent: (() => void) | null = null;

function scrollToBottom() {
	nextTick(() => {
		const el = listRef.value;
		if (el) el.scrollTop = el.scrollHeight;
	});
}

function append(role: 'user' | 'ai', content: string) {
	messages.value.push({ role, content });
	scrollToBottom();
}

function handleSend() {
	const text = input.value.trim();
	if (!text || isStreaming.value) return;
	append('user', text);
	input.value = '';
	isStreaming.value = true;
	// 启动 SSE
	stopCurrent = props.startStream(text);
}

function newline() {
	// 仅用于阻止默认行为说明
}

// 供父组件在流式期间追加 AI 文本块
function appendAiChunk(chunk: string) {
	const last = messages.value[messages.value.length - 1];
	if (!last || last.role !== 'ai') {
		messages.value.push({ role: 'ai', content: chunk });
	} else {
		last.content += chunk;
	}
	scrollToBottom();
}

// 供父组件在流式结束时调用
function endStream() {
	isStreaming.value = false;
	stopCurrent?.();
	stopCurrent = null;
}

defineExpose({ appendAiChunk, endStream, append });

onBeforeUnmount(() => {
	stopCurrent?.();
});

watch(messages, scrollToBottom, { deep: true });
</script>

<style scoped>
</style>


